using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.Data;

namespace RaidLog.Engine.LogParser
{
    public class LogParser<TDataSet> where TDataSet : DataSet, new()
    {
        #region Fields and Properties

        LogParsePatterns _LogParsePatterns = null;
        TDataSet _Data = null;
        int _LineNumber = 0;

        public LogParsePatterns LogParsePatterns
        {
            get { return _LogParsePatterns; }
        }

        public TDataSet Data
        {
            get { return _Data; }
        }

        public int LineNumber
        {
            get { return _LineNumber; }
        }

        #endregion

        public LogParser(string _translationDataPath)
        {
            _LogParsePatterns = Util.ReadData<LogParsePatterns>(_translationDataPath);
            _Data = new TDataSet();
        }

        public void ParseLine(string thisLine)
        {
            ParseLine(_LineNumber++, _LogParsePatterns, thisLine, _Data);
        }

        public void ParseLine(string[] thisLines)
        {
            foreach(string thisLine in thisLines)
            {
                ParseLine(_LineNumber++, _LogParsePatterns, thisLine, _Data);
            }
        }

        public static void ParseLine(int lineNumber, LogParsePatterns _LogParsePatterns, string thisLine, System.Data.DataSet data)
        {
            bool matched = false;
            bool indented = false;
            foreach (LogParsePattern logParsePattern in _LogParsePatterns.Patterns)
            {
                try
                {
                    if (matched && logParsePattern.Exclusive) continue;
                    Regex regex = new Regex(logParsePattern.RegularExpression);
                    Match match = regex.Match(thisLine);
                    if (match.Success)
                    {
                        matched |= logParsePattern.Exclusive;
                        if (!indented)
                        {
                            indented = true;
                            //Trace.WriteLine("Match: " + thisLine);
                            Trace.Indent();
                        }
                        //Trace.WriteLine(logParsePattern.RegularExpression);

                        DataRow row = data.Tables[logParsePattern.TargetTable].NewRow();

                        foreach (LogParsePatternReplacement logParsePatternReplacement in logParsePattern.Values)
                        {
                            string value = logParsePatternReplacement.Value;
                            for (int i = 1; i < match.Groups.Count; i++)
                            {
                                value = Regex.Replace(value, @"\{" + i.ToString() + @"\}", match.Groups[i].Value);
                            }
                            value = Regex.Replace(value, @"\#", lineNumber.ToString());

                            if (logParsePatternReplacement.Column == "$")
                            {
                                thisLine = regex.Replace(thisLine, value);
                                continue;
                            }

                            if (!data.Tables.Contains(logParsePattern.TargetTable))
                            {
                                throw new ApplicationException("Table Not Found: " + logParsePattern.TargetTable);
                            }

                            if (!data.Tables[logParsePattern.TargetTable].Columns.Contains(logParsePatternReplacement.Column))
                            {
                                throw new ApplicationException("Column Not Found: " + logParsePatternReplacement.Column);
                            }

                            string columnType = data.Tables[logParsePattern.TargetTable].Columns[logParsePatternReplacement.Column].DataType.ToString();
                            switch (columnType)
                            {
                                case "System.String":
                                    row[logParsePatternReplacement.Column] = value;
                                    break;
                                case "System.Int32":
                                    row[logParsePatternReplacement.Column] = Int32.Parse(value);
                                    break;
                                case "System.DateTime":
                                    row[logParsePatternReplacement.Column] = DateTime.Parse(value);
                                    break;
                                case "System.Boolean":
                                    row[logParsePatternReplacement.Column] = Boolean.Parse(value);
                                    break;
                                default:
                                    throw new NotImplementedException("Cannot parse string to type: " + columnType);
                            }
                        }
                        data.Tables[logParsePattern.TargetTable].Rows.Add(row);
                    }
                }
                catch (Exception ex)
                {
                    Trace.WriteLine(ex.ToString());
                }
            }
            if (indented)
            {
                indented = false;
                Trace.Unindent();
            }
            if (!matched)
            {
                //Trace.WriteLine("No Match: " + thisLine);
            }
        }
    }
}
